<!DOCTYPE html>
<html>
<head>
    

    

    



    <meta charset="utf-8">
    
    
    
    <title>Android架构组件(四)-LiveData | 随手记 | 不积跬步无以至千里</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
    <meta name="theme-color" content="#1c9d5c">
    
    
    <meta name="keywords" content="Android,Architecture Components,LiveData">
    <meta name="description" content="LiveData是一个可被观察的数据持有类。不同于常规的observable，LiveData是生命周期敏感的，也就意味着它尊重其他组件的生命周期，比如activities, fragments，或者services。这种特性确保了LiveData只会在一个激活的生命周期状态下更新应用组件下的observers。 如果观察者的生命周期处于STARTED或RESUMED状态，则LiveData会将O">
<meta name="keywords" content="Android,Architecture Components,LiveData">
<meta property="og:type" content="article">
<meta property="og:title" content="Android架构组件(四)-LiveData">
<meta property="og:url" content="http://yoursite.com/2017/09/21/architecture-livedata/index.html">
<meta property="og:site_name" content="随手记">
<meta property="og:description" content="LiveData是一个可被观察的数据持有类。不同于常规的observable，LiveData是生命周期敏感的，也就意味着它尊重其他组件的生命周期，比如activities, fragments，或者services。这种特性确保了LiveData只会在一个激活的生命周期状态下更新应用组件下的observers。 如果观察者的生命周期处于STARTED或RESUMED状态，则LiveData会将O">
<meta property="og:locale" content="zh-CN">
<meta property="og:updated_time" content="2018-04-11T08:50:36.064Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Android架构组件(四)-LiveData">
<meta name="twitter:description" content="LiveData是一个可被观察的数据持有类。不同于常规的observable，LiveData是生命周期敏感的，也就意味着它尊重其他组件的生命周期，比如activities, fragments，或者services。这种特性确保了LiveData只会在一个激活的生命周期状态下更新应用组件下的observers。 如果观察者的生命周期处于STARTED或RESUMED状态，则LiveData会将O">
    
        <link rel="alternate" type="application/atom+xml" title="随手记" href="/atom.xml">
    
    <link rel="shortcut icon" href="/favicon.ico">
    <link rel="stylesheet" href="/css/style.css?v=1.7.2">
    <script>window.lazyScripts=[]</script>

    <!-- custom head -->
    

</head>

<body>
    <div id="loading" class="active"></div>

    <aside id="menu" class="hide" >
  <div class="inner flex-row-vertical">
    <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menu-off">
        <i class="icon icon-lg icon-close"></i>
    </a>
    <div class="brand-wrap" style="background-image:url(/img/brand.jpg)">
      <div class="brand">
        <a href="/" class="avatar waves-effect waves-circle waves-light">
          <img src="/img/avatar.jpg">
        </a>
        <hgroup class="introduce">
          <h5 class="nickname">马建</h5>
          <a href="mailto:markjoker@126.com" title="markjoker@126.com" class="mail">markjoker@126.com</a>
        </hgroup>
      </div>
    </div>
    <div class="scroll-wrap flex-col">
      <ul class="nav">
        
            <li class="waves-block waves-effect">
              <a href="/"  >
                <i class="icon icon-lg icon-home"></i>
                主页
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/archives"  >
                <i class="icon icon-lg icon-archives"></i>
                归档
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/tags"  >
                <i class="icon icon-lg icon-tags"></i>
                标签
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/categories"  >
                <i class="icon icon-lg icon-th-list"></i>
                分类
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="https://github.com/markjoker" target="_blank" >
                <i class="icon icon-lg icon-github"></i>
                Github
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="http://www.weibo.com/markjoker" target="_blank" >
                <i class="icon icon-lg icon-weibo"></i>
                微博
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/cv"  >
                <i class="icon icon-lg icon-file"></i>
                简历
              </a>
            </li>
        
      </ul>
    </div>
  </div>
</aside>

    <main id="main">
        <header class="top-header" id="header">
    <div class="flex-row">
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light on" id="menu-toggle">
          <i class="icon icon-lg icon-navicon"></i>
        </a>
        <div class="flex-col header-title ellipsis">Android架构组件(四)-LiveData</div>
        
        <div class="search-wrap" id="search-wrap">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
                <i class="icon icon-lg icon-chevron-left"></i>
            </a>
            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="search">
                <i class="icon icon-lg icon-search"></i>
            </a>
        </div>
        
        
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menuShare">
            <i class="icon icon-lg icon-share-alt"></i>
        </a>
        
    </div>
</header>
<header class="content-header post-header">

    <div class="container fade-scale">
        <h1 class="title">Android架构组件(四)-LiveData</h1>
        <h5 class="subtitle">
            
                <time datetime="2017-09-21T11:44:55.000Z" itemprop="datePublished" class="page-time">
  2017-09-21
</time>


            
        </h5>
    </div>

    


</header>


<div class="container body-wrap">
    
    <aside class="post-widget">
        <nav class="post-toc-wrap post-toc-shrink" id="post-toc">
            <h4>目录</h4>
            <ol class="post-toc"><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#LiveData的优点"><span class="post-toc-number">1.</span> <span class="post-toc-text">LiveData的优点</span></a></li><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#使用LiveData对象"><span class="post-toc-number">2.</span> <span class="post-toc-text">使用LiveData对象</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#创建LiveData对象"><span class="post-toc-number">2.1.</span> <span class="post-toc-text">创建LiveData对象</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#观察LiveData对象"><span class="post-toc-number">2.2.</span> <span class="post-toc-text">观察LiveData对象</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#更新LiveData对象"><span class="post-toc-number">2.3.</span> <span class="post-toc-text">更新LiveData对象</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#结合Room使用LiveData"><span class="post-toc-number">2.4.</span> <span class="post-toc-text">结合Room使用LiveData</span></a></li></ol></li><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#扩展LiveData"><span class="post-toc-number">3.</span> <span class="post-toc-text">扩展LiveData</span></a></li><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#转换LiveData"><span class="post-toc-number">4.</span> <span class="post-toc-text">转换LiveData</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#创建新的转换"><span class="post-toc-number">4.1.</span> <span class="post-toc-text">创建新的转换</span></a></li></ol></li><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#合并多个LiveData源"><span class="post-toc-number">5.</span> <span class="post-toc-text">合并多个LiveData源</span></a></li></ol>
        </nav>
    </aside>


<article id="post-architecture-livedata"
  class="post-article article-type-post fade" itemprop="blogPost">

    <div class="post-card">
        <h1 class="post-card-title">Android架构组件(四)-LiveData</h1>
        <div class="post-meta">
            <time class="post-time" title="2017-09-21 19:44:55" datetime="2017-09-21T11:44:55.000Z"  itemprop="datePublished">2017-09-21</time>

            


            
<span id="busuanzi_container_page_pv" title="文章总阅读量" style='display:none'>
    <i class="icon icon-eye icon-pr"></i><span id="busuanzi_value_page_pv"></span>
</span>


        </div>
        <div class="post-content" id="post-content" itemprop="postContent">
            <p><code>LiveData</code>是一个可被观察的数据持有类。不同于常规的observable，LiveData是生命周期敏感的，也就意味着它尊重其他组件的生命周期，比如activities, fragments，或者services。这种特性确保了LiveData只会在一个激活的生命周期状态下更新应用组件下的observers。</p>
<p>如果观察者的生命周期处于<code>STARTED</code>或<code>RESUMED</code>状态，则<code>LiveData</code>会将<code>Observer</code>类表示的观察者视为活动状态。<code>LiveData</code>只会通知那些处于活动状态的observers去更新。那些注册了观察<code>LiveData</code>但是处于非活动状态的observers不会收到改变的通知。</p>
<p>您可以注册与实现<code>LifecycleOwner</code>接口的对象配对的观察者。此关系允许在相应生命周期对象的状态更改为<code>DESTROYED</code>时删除观察者。这对于activities和fragments特别有用，因为它们可以安全地观察LiveData对象，而不必担心泄漏 - 在其生命周期被破坏时，activities和fragments会立即取消订阅。</p>
<h1 id="LiveData的优点"><a href="#LiveData的优点" class="headerlink" title="LiveData的优点"></a>LiveData的优点</h1><hr>
<p>使用LiveData能够带来如下优点：</p>
<ul>
<li><strong>确保你的UI和数据状态匹配</strong><br>LiveData遵循观察者模式。当生命周期状态发生变化时，LiveData会通知观察者对象。您可以整合更新UI的代码到这些观察者对象中。在每次应用程序数据改变时，你的观察者可以更新UI，而不是每次更新的时候更新UI。</li>
<li><strong>避免内存溢出</strong><br>观察者被绑定到Lifecycle对象，当他们的相关生命周期处于destroyed时，他们会自我清理。</li>
<li><strong>避免activities停止带来的崩溃问题</strong><br>如果观察者的生命周期是不活动的，比如在后台堆栈中的活动，那么它就不会接收到任何LiveData事件。</li>
<li><strong>避免过多的生命周期手动处理</strong><br>UI组件只观察相关数据而不会去停止或恢复观察。LiveData自动管理所有这些，因为它在observing期间能够意识到相关生命周期状态的变化。</li>
<li><strong>始终保持最新的数据</strong><br>如果生命周期变得不活跃，当再次激活的时候它会接收到最新数据。例如，后台的活动在返回到前台后接收最新的数据。</li>
<li><strong>正确的配置更改</strong><br>如果一个Activity或者Fragment由于类似设备旋转等配置更改造成重新创建，它会立马接收到最新的可用数据。</li>
<li><strong>共享资源</strong><br>您可以使用单例模式扩展LiveData对象，以封装系统服务，以便在应用程序中共享它们。LiveData对象连接到系统服务一次，然后任何需要该资源的观察者只需观察LiveData对象。</li>
</ul>
<h1 id="使用LiveData对象"><a href="#使用LiveData对象" class="headerlink" title="使用LiveData对象"></a>使用LiveData对象</h1><hr>
<p>通过以下步骤学习使用<code>LiveData</code>对象：</p>
<ol>
<li>创建一个LiveData实例来保存某种类型的数据。这通常在您的<code>ViewModel</code>类中完成。</li>
<li>创建一个Observer对象，该对象定义<code>onChanged()</code>方法，该方法控制在<code>LiveData</code>对象的数据更改时需要进行的操作。您通常在UI控制器中创建一个观察者对象，例如一个activity或者fragment。</li>
<li>使用<code>observe()</code>方法将<code>Observer</code>对象连接到LiveData对象。<code>observe()</code>方法使用一个<code>LifecycleOwner</code>对象。它将Observer对象订阅到LiveData对象，以便通知更改。您通常将Observer对象附加在UI控制器中，例如activity或fragment。<blockquote>
<p><strong>注意：</strong>您可以使用<code>observeForever(Observer)</code>方法在没有关联的<code>LifecycleOwner</code>对象的情况下注册一个观察者。在这种情况下，观察者被认为总是处于活动状态，因此总是被告知修改。您可以删除调用<code>removeObserver(Observer)</code>方法的这些observers。</p>
</blockquote>
</li>
</ol>
<p>当您更新LiveData对象中存储的值时，只要附加的LifecycleOwner对象处于活动状态，它就会触发所有已注册的observers。<br>LiveData允许UI控制器里面的observers订阅更新。当LiveData对象所持有的数据发生变化时，UI会自动响应更新。</p>
<h2 id="创建LiveData对象"><a href="#创建LiveData对象" class="headerlink" title="创建LiveData对象"></a>创建LiveData对象</h2><p>LiveData是一个可以用于任何数据的包装器，包括实现<code>Collections</code>的对象，如<code>List</code>。<code>LiveData</code>对象通常存储在<code>ViewModel</code>对象中，并通过getter方法进行访问，如所示：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NameViewModel</span> <span class="keyword">extends</span> <span class="title">ViewModel</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Create a LiveData with a String</span></span><br><span class="line"><span class="keyword">private</span> MutableLiveData&lt;String&gt; mCurrentName;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> MutableLiveData&lt;String&gt; <span class="title">getCurrentName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (mCurrentName == <span class="keyword">null</span>) &#123;</span><br><span class="line">            mCurrentName = <span class="keyword">new</span> MutableLiveData&lt;String&gt;();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> mCurrentName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Rest of the ViewModel...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>开始，LiveData对象中的数据没有设置。</p>
<blockquote>
<p><strong>注意：</strong>确保是在ViewModel对象中存储更新UI的LiveData对象，而不是activity或fragment，原因如下:</p>
<ul>
<li>避免膨胀的activities和fragments。现在，这些UI控制器负责显示数据，而不是保存数据状态。 </li>
<li>将LiveData实例与特定activity或fragment实例分离，可以确保LiveData对象在配置更改中（比如旋转屏幕）存活。</li>
</ul>
</blockquote>
<h2 id="观察LiveData对象"><a href="#观察LiveData对象" class="headerlink" title="观察LiveData对象"></a>观察LiveData对象</h2><p>在大多数情况下，应用程序组件的<code>onCreate()</code>方法是开始观察LiveData对象的正确位置，原因如下:</p>
<ul>
<li>为了确保系统不会从一个activity或者fragment的onResume()方法中发出冗余的调用。</li>
<li>为了确保activity或者fragment拥有数据，它可以在活动开始时显示。一旦应用程序组件处于活动状态，它就会从它所观察到的LiveData对象中接收到最新的值。只有在已被observed的LiveData对象被设置时才会出现这种情况</li>
</ul>
<p>一般来说，LiveData只在数据发生变化时才提供更新，而且只对活动的observers进行更新。这种行为的一个例外是，当观察者从一个非活动状态转变为一个活动状态时，也会收到一个更新。此外，如果观察者第二次从非活动状态变为活动状态，如果该值在上一次激活时发生了变化，它也只会收到一个更新。</p>
<p>以下示例代码说明了如何开始观察一个<code>LiveData</code>对象：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NameActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> NameViewModel mModel;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Other code to setup the activity...</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// Get the ViewModel.</span></span><br><span class="line">        mModel = ViewModelProviders.of(<span class="keyword">this</span>).get(NameViewModel.class);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Create the observer which updates the UI.</span></span><br><span class="line">        <span class="keyword">final</span> Observer&lt;String&gt; nameObserver = <span class="keyword">new</span> Observer&lt;String&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onChanged</span><span class="params">(@Nullable <span class="keyword">final</span> String newName)</span> </span>&#123;</span><br><span class="line">                <span class="comment">// Update the UI, in this case, a TextView.</span></span><br><span class="line">                mNameTextView.setText(newName);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.</span></span><br><span class="line">        mModel.getCurrentName().observe(<span class="keyword">this</span>, nameObserver);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>在使用nameObserver作为参数传递了<code>observe()</code>方法后，<code>onChanged()</code>方法将会被立即调用，以提供当前在mCurrentName中存储的最新值。<br>如果LiveData对象没有给mCurrentName设置值，则不会调用<code>onChanged()</code>。</p>
<h2 id="更新LiveData对象"><a href="#更新LiveData对象" class="headerlink" title="更新LiveData对象"></a>更新LiveData对象</h2><p><code>LiveData</code>没有公开可用的方法来更新存储的数据。<code>MutableLiveData</code>类公开了<code>setValue(T)</code>和<code>postValue(T)</code>方法，如果需要编辑存储在<code>LiveData</code>对象中的值，则必须使用这些方法。通常在<code>ViewModel</code>中使用<code>MutableLiveData</code>，然后<code>ViewModel</code>只向observers公开不可变的LiveData对象。<br>在设置了observer关系之后，您可以更新<code>LiveData</code>对象的值，如下面的例子所示，当用户点击一个按钮时，它会触发所有观察者。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">mButton.setOnClickListener(<span class="keyword">new</span> OnClickListener() &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View v)</span> </span>&#123;</span><br><span class="line">        String anotherName = <span class="string">"John Doe"</span>;</span><br><span class="line">        mModel.getCurrentName().setValue(anotherName);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p>在示例中调用<code>setValue(T)</code>结果是<code>observers</code>调用了<code>onChanged()</code>方法，并且<code>onChanged()</code>方法参数的值为John Doe。这个示例显示了一个按钮按下，但是<code>setValue()</code>或<code>postValue()</code>可以被调用以各种原因更新mName，包括响应网络请求或数据库加载完成;<br>在所有情况下，对<code>setValue()</code>或<code>postValue()</code>的调用会触发观察者并更新UI。</p>
<blockquote>
<p><strong>注意：</strong>调用setValue(T)方法更新LiveData对象只能在主线程中。如果代码是在一个工作线程中执行的，那么您可以使用postValue(T)方法来更新LiveData对象。</p>
</blockquote>
<h2 id="结合Room使用LiveData"><a href="#结合Room使用LiveData" class="headerlink" title="结合Room使用LiveData"></a>结合Room使用LiveData</h2><p><code>Room</code>持久化库支持observable的查询，这些查询返回了LiveData对象。observable的查询是作为数据库访问对象(DAO)的一部分编写的。</p>
<p>当数据库被更新时，Room会生成所有必要的代码来更新LiveData对象。当需要时，生成的代码在后台线程上异步地运行查询。此模式有助于将数据显示在UI中，与存储在数据库中的数据保持同步。您可以在Room的持久化库指南中了解更多关于Room和dao的内容。</p>
<h1 id="扩展LiveData"><a href="#扩展LiveData" class="headerlink" title="扩展LiveData"></a>扩展LiveData</h1><hr>
<p>LiveData认为如果observer的生命周期处于STARTED或RESUMED状态，那么observer处于活动状态，以下示例代码说明了如何扩展LiveData类:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StockLiveData</span> <span class="keyword">extends</span> <span class="title">LiveData</span>&lt;<span class="title">BigDecimal</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> StockManager mStockManager;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> SimplePriceListener mListener = <span class="keyword">new</span> SimplePriceListener() &#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onPriceChanged</span><span class="params">(BigDecimal price)</span> </span>&#123;</span><br><span class="line">            setValue(price);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">StockLiveData</span><span class="params">(String symbol)</span> </span>&#123;</span><br><span class="line">        mStockManager = <span class="keyword">new</span> StockManager(symbol);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onActive</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mStockManager.requestPriceUpdates(mListener);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onInactive</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mStockManager.removeUpdates(mListener);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>本示例中的价格监听器的实现包括以下重要方法:</p>
<ul>
<li>当<code>LiveData</code>对象有一个活动的观察者时，就会调用<code>onActive()</code>方法。这意味着您需要从这个方法开始观察股票价格的更新。</li>
<li>当<code>LiveData</code>对象没有任何活动的观察者时，就会调用<code>onInactive()</code>方法。由于没有observers在监听，因此没有理由与StockManager服务保持联系。</li>
<li><code>setValue(T)</code>方法更新<code>LiveData</code>实例的值，并通知任何活动的观察者关于这个变化。<br>你可以像下面代码这样使用<code>StockLiveData</code>类：<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyFragment</span> <span class="keyword">extends</span> <span class="title">Fragment</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onActivityCreated</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onActivityCreated(savedInstanceState);</span><br><span class="line">        LiveData&lt;BigDecimal&gt; myPriceListener = ...;</span><br><span class="line">        myPriceListener.observe(<span class="keyword">this</span>, price -&gt; &#123;</span><br><span class="line">            <span class="comment">// Update the UI.</span></span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>把fragment作为<code>observe()</code>方法的第一个参数，该fragment是<code>LifecycleOwner</code>的一个实例。这样做意味着这个观察者被绑定到fragment相关的Lifecycle对象，这意味着:</p>
<ul>
<li>如果Lifecycle对象不是处于活动状态，那么即使值发生变化，也不会调用观察者。</li>
<li>在Lifecycle对象被销毁后，observer也会被自动移除。<br>实际上LiveData对象是生命周期敏感的，这意味着您可以在多个activities、fragments和services之间共享它们。为了保持这个示例的简单性，您可以将LiveData类作为一个单例对象来实现:<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StockLiveData</span> <span class="keyword">extends</span> <span class="title">LiveData</span>&lt;<span class="title">BigDecimal</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> StockLiveData sInstance;</span><br><span class="line">    <span class="keyword">private</span> StockManager mStockManager;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> SimplePriceListener mListener = <span class="keyword">new</span> SimplePriceListener() &#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onPriceChanged</span><span class="params">(BigDecimal price)</span> </span>&#123;</span><br><span class="line">            setValue(price);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@MainThread</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> StockLiveData <span class="title">get</span><span class="params">(String symbol)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (sInstance == <span class="keyword">null</span>) &#123;</span><br><span class="line">            sInstance = <span class="keyword">new</span> StockLiveData(symbol);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> sInstance;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">StockLiveData</span><span class="params">(String symbol)</span> </span>&#123;</span><br><span class="line">        mStockManager = <span class="keyword">new</span> StockManager(symbol);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onActive</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mStockManager.requestPriceUpdates(mListener);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onInactive</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mStockManager.removeUpdates(mListener);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>然后你可以再fragment中这样使用它：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyFragment</span> <span class="keyword">extends</span> <span class="title">Fragment</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onActivityCreated</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        StockLiveData.get(getActivity()).observe(<span class="keyword">this</span>, price -&gt; &#123;</span><br><span class="line">            <span class="comment">// Update the UI.</span></span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>多个fragments和activities可以观察到MyPriceListener实例。LiveData只有在其中一个或多个具有可见性和活动性时才连接到系统服务。</p>
<h1 id="转换LiveData"><a href="#转换LiveData" class="headerlink" title="转换LiveData"></a>转换LiveData</h1><hr>
<p>您可能想要对LiveData对象中存储的值进行更改，然后将其发送给observers，或者您可能需要根据另一个对象的值返回一个不同的LiveData实例。Lifecycle package提供了<code>Transformations</code>，其中包括支持这些场景的帮助方法。<br><strong>Transformations.map()</strong><br>对存储在<code>LiveData</code>对象中的值应用一个函数，并将结果传播到下游。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">LiveData&lt;User&gt; userLiveData = ...;</span><br><span class="line">LiveData&lt;String&gt; userName = Transformations.map(userLiveData, user -&gt; &#123;</span><br><span class="line">    user.name + <span class="string">" "</span> + user.lastName</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p><strong>Transformations.switchMap()</strong><br>与<code>map()</code>类似，将一个函数应用到<code>LiveData</code>对象中存储的值，并将结果发送到下游。传递给<code>switchMap()</code>方法的函数(匿名内部类)必须返回一个<code>LiveData</code>对象，如下面的例子所示:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> LiveData&lt;User&gt; <span class="title">getUser</span><span class="params">(String id)</span> </span>&#123;</span><br><span class="line">  ...;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">LiveData&lt;String&gt; userId = ...;</span><br><span class="line">LiveData&lt;User&gt; user = Transformations.switchMap(userId, id -&gt; getUser(id) );</span><br></pre></td></tr></table></figure></p>
<p>如果您认为在<code>ViewModel</code>对象中需要一个Lifecycle对象，那么<code>transformation</code>可能是更好的解决方案。例如，假设您有一个UI组件，该组件接受一个地址，并返回该地址的邮政编码。您可以为该组件实现简单的<code>ViewModel</code>，如下示例代码所示:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyViewModel</span> <span class="keyword">extends</span> <span class="title">ViewModel</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> PostalCodeRepository repository;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyViewModel</span><span class="params">(PostalCodeRepository repository)</span> </span>&#123;</span><br><span class="line">       <span class="keyword">this</span>.repository = repository;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> LiveData&lt;String&gt; <span class="title">getPostalCode</span><span class="params">(String address)</span> </span>&#123;</span><br><span class="line">       <span class="comment">// DON'T DO THIS</span></span><br><span class="line">       <span class="keyword">return</span> repository.getPostCode(address);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>然后，UI组件需要从先前的<code>LiveData</code>对象中取消注册，并在每次调用<code>getPostalCode()</code>时注册到新实例。此外，如果UI组件被重新创建，它将触发另一个<code>repository.getpostcode()</code>方法的调用，而不是使用以前的调用的结果。</p>
<p>相反的，您可以实现邮政编码查找作为地址输入的transformation，如下面的示例所示:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyViewModel</span> <span class="keyword">extends</span> <span class="title">ViewModel</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> PostalCodeRepository repository;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> MutableLiveData&lt;String&gt; addressInput = <span class="keyword">new</span> MutableLiveData();</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> LiveData&lt;String&gt; postalCode =</span><br><span class="line">            Transformations.switchMap(addressInput, (address) -&gt; &#123;</span><br><span class="line">                <span class="keyword">return</span> repository.getPostCode(address);</span><br><span class="line">             &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">MyViewModel</span><span class="params">(PostalCodeRepository repository)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.repository = repository</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">setInput</span><span class="params">(String address)</span> </span>&#123;</span><br><span class="line">      addressInput.setValue(address);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>在本例中，postalCode字段是public的和final的，因为字段永远不会更改。postalCode字段被定义为addressInput的转换，这意味着在addressInput发生变化时调用了<code>repository.getPostCode()</code>方法。上述的情况在有一个活动的观observer情况下是正确的，而如果<code>repository.getPostCode()</code>被调用时没有一个活动状态的observer，那么是不会发生计算，直到添加一个观察。<br>该机制允许应用程序的较低级别创建基于需求的延迟计算的LiveData对象。ViewModel对象可以很容易地获得对LiveData对象的引用，然后在它们上面定义transformation规则。</p>
<h2 id="创建新的转换"><a href="#创建新的转换" class="headerlink" title="创建新的转换"></a>创建新的转换</h2><p>在你的应用中有十几个不同的具体的transformation，但它们不是默认提供的。为了实现您自己的转换，您可以使用MediatorLiveData类，它listens其他的LiveData对象，并处理它们发出的事件。MediatorLiveData正确地将其状态传播到源LiveData对象。</p>
<h1 id="合并多个LiveData源"><a href="#合并多个LiveData源" class="headerlink" title="合并多个LiveData源"></a>合并多个LiveData源</h1><hr>
<p><code>MediatorLiveData</code>是<code>LiveData</code>的一个子类，它允许您合并多个LiveData数据源。当任何原始的LiveData数据源对象发生变化时，MediatorLiveData对象的观察者就会被触发。<br>例如，如果您的UI中有一个LiveData对象，可以从本地数据库或网络更新，那么您可以将以下源添加到MediatorLiveData对象:</p>
<ul>
<li>一个<code>LiveData</code>对象与数据库相关联。</li>
<li>一个<code>LiveData</code>对象与网络访问相关联。<br>您的activity只需要观察<code>MediatorLiveData</code>对象来接收来自两个源的更新。</li>
</ul>

        </div>

        <blockquote class="post-copyright">
    
    <div class="content">
        
<span class="post-time">
    最后更新时间：<time datetime="2018-04-11T08:50:36.064Z" itemprop="dateUpdated">2018-04-11 16:50:36</time>
</span><br>


        
        如有错误，请留言指正。
        
    </div>
    
    <footer>
        <a href="http://yoursite.com">
            <img src="/img/avatar.jpg" alt="马建">
            马建
        </a>
    </footer>
</blockquote>

        
<div class="page-reward">
    <a id="rewardBtn" href="javascript:;" class="page-reward-btn waves-effect waves-circle waves-light">赏</a>
</div>



        <div class="post-footer">
            
	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Android/">Android</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Architecture-Components/">Architecture Components</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/LiveData/">LiveData</a></li></ul>


            
<div class="page-share-wrap">
    

<div class="page-share" id="pageShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://yoursite.com/2017/09/21/architecture-livedata/&title=《Android架构组件(四)-LiveData》 — 随手记&pic=http://yoursite.com/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://yoursite.com/2017/09/21/architecture-livedata/&title=《Android架构组件(四)-LiveData》 — 随手记&source=desc" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://yoursite.com/2017/09/21/architecture-livedata/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《Android架构组件(四)-LiveData》 — 随手记&url=http://yoursite.com/2017/09/21/architecture-livedata/&via=http://yoursite.com" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://yoursite.com/2017/09/21/architecture-livedata/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>



    <a href="javascript:;" id="shareFab" class="page-share-fab waves-effect waves-circle">
        <i class="icon icon-share-alt icon-lg"></i>
    </a>
</div>



        </div>
    </div>

    
<nav class="post-nav flex-row flex-justify-between">
  
    <div class="waves-block waves-effect prev">
      <a href="/2017/09/25/architecture-viewmodel/" id="post-prev" class="post-nav-link">
        <div class="tips"><i class="icon icon-angle-left icon-lg icon-pr"></i> Prev</div>
        <h4 class="title">Android架构组件(五)-ViewModel</h4>
      </a>
    </div>
  

  
    <div class="waves-block waves-effect next">
      <a href="/2017/09/15/architecture-lifecycle/" id="post-next" class="post-nav-link">
        <div class="tips">Next <i class="icon icon-angle-right icon-lg icon-pl"></i></div>
        <h4 class="title">Android架构组件(三)-生命周期</h4>
      </a>
    </div>
  
</nav>



    














</article>

<div id="reward" class="page-modal reward-lay">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <h3 class="reward-title">
        <i class="icon icon-quote-left"></i>
        谢谢大爷~
        <i class="icon icon-quote-right"></i>
    </h3>
    <div class="reward-content">
        
        <div class="reward-code">
            <img id="rewardCode" src="/img/wechat.jpg" alt="打赏二维码">
        </div>
        
        <label class="reward-toggle">
            <input id="rewardToggle" type="checkbox" class="reward-toggle-check"
                data-wechat="/img/wechat.jpg" data-alipay="/img/alipay.jpg">
            <div class="reward-toggle-ctrol">
                <span class="reward-toggle-item wechat">微信</span>
                <span class="reward-toggle-label"></span>
                <span class="reward-toggle-item alipay">支付宝</span>
            </div>
        </label>
        
    </div>
</div>



</div>

        <footer class="footer">
    <div class="top">
        
<p>
    <span id="busuanzi_container_site_uv" style='display:none'>
        站点总访客数：<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv" style='display:none'>
        站点总访问量：<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


        <p>
            
                <span><a href="/atom.xml" target="_blank" class="rss" title="rss"><i class="icon icon-lg icon-rss"></i></a></span>
            
            <span>博客内容遵循 <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span>
        </p>
    </div>
    <div class="bottom">
        <p><span>马建 &copy; 2015 - 2019</span>
            <span>
                
            </span>
        </p>
    </div>
</footer>

    </main>
    <div class="mask" id="mask"></div>
<a href="javascript:;" id="gotop" class="waves-effect waves-circle waves-light"><span class="icon icon-lg icon-chevron-up"></span></a>



<div class="global-share" id="globalShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://yoursite.com/2017/09/21/architecture-livedata/&title=《Android架构组件(四)-LiveData》 — 随手记&pic=http://yoursite.com/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://yoursite.com/2017/09/21/architecture-livedata/&title=《Android架构组件(四)-LiveData》 — 随手记&source=desc" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://yoursite.com/2017/09/21/architecture-livedata/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《Android架构组件(四)-LiveData》 — 随手记&url=http://yoursite.com/2017/09/21/architecture-livedata/&via=http://yoursite.com" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://yoursite.com/2017/09/21/architecture-livedata/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>


<div class="page-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <img src="" alt="微信分享二维码">
</div>




    <script src="//cdn.bootcss.com/node-waves/0.7.4/waves.min.js"></script>
<script>
var BLOG = { ROOT: '/', SHARE: true, REWARD: true };


</script>

<script src="/js/main.min.js?v=1.7.2"></script>


<div class="search-panel" id="search-panel">
    <ul class="search-result" id="search-result"></ul>
</div>
<template id="search-tpl">
<li class="item">
    <a href="{path}" class="waves-block waves-effect">
        <div class="title ellipsis" title="{title}">{title}</div>
        <div class="flex-row flex-middle">
            <div class="tags ellipsis">
                {tags}
            </div>
            <time class="flex-col time">{date}</time>
        </div>
    </a>
</li>
</template>

<script src="/js/search.min.js?v=1.7.2" async></script>






<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>



<script>
(function() {
    var OriginTitile = document.title, titleTime;
    document.addEventListener('visibilitychange', function() {
        if (document.hidden) {
            document.title = '随手记';
            clearTimeout(titleTime);
        } else {
            document.title = '随手记';
            titleTime = setTimeout(function() {
                document.title = OriginTitile;
            },2000);
        }
    });
})();
</script>



</body>
</html>
